/*
 * Copyright (C) 2009 Rafael Fernandes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phonebooksharing.services.servlets;

import java.awt.Toolkit;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

import javax.ejb.EJB;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.phonebooksharing.dto.ReturnItem;
import com.phonebooksharing.services.ejb3.facade.ProfileFacade;
import com.phonebooksharing.services.ejb3.utils.IConstants;
import com.phonebooksharing.services.utils.IOUtilities;
import com.phonebooksharing.services.utils.Thumbnail;

/**
 * Servlet implementation class DashboardServlet
 */
public class VideoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public VideoServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//	    PrintWriter pw = response.getWriter();
//        response.setContentType("text/html");
//        pw.print("<html><head/><body><h1>Welcome to Phonebook Sharing Services! </h1></body></html>");
	    doPost(request, response);
	}
	
	@EJB
    private ProfileFacade profileFacade;

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
	    
	    try {
            final String ac = request.getParameter("ac");
            if ("v".equalsIgnoreCase(ac)) {//video
                ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                final String authItem = (String) ois.readObject();

                ObjectOutputStream oos = new ObjectOutputStream(resp.getOutputStream());

                final String q = request.getParameter("q");
                if("s".equalsIgnoreCase(q)) {
                    oos.writeObject(profileFacade.getSharingVideos(authItem));
                } else if("ns".equalsIgnoreCase(q)) {
                    oos.writeObject(profileFacade.getNonSharingVideos(authItem));
                } else if("a".equalsIgnoreCase(q)) {//list of all images on the server
                    oos.writeObject(profileFacade.getVideoGalleryDeviceIdList(authItem));
                }
            } else if("uv".equalsIgnoreCase(ac)) {//upload video
                final String q = request.getParameter("q");
                final String mt = request.getParameter("mt");

                profileFacade.setVideoPathToVideoGallery(new Long(q), uploadVideo(request, resp, q, mt));
            } else if("utv".equalsIgnoreCase(ac)) {//upload thumb video
                final String q  = request.getParameter("q"),
                             mt = request.getParameter("mt"),
                             h  = request.getParameter("h");

                if("1".equalsIgnoreCase(h)) {
                    profileFacade.setVideoThumbPathToVideoGallery(new Long(q), null);
                } else {
                    profileFacade.setVideoThumbPathToVideoGallery(new Long(q), uploadVideo(request, resp, q, mt));
                }
                
                ObjectOutputStream oos = new ObjectOutputStream(resp.getOutputStream());
                oos.writeObject(new ReturnItem(true));
            } else if("gvl".equalsIgnoreCase(ac)) {//get video list
                ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                final String authItem = (String) ois.readObject();
                final int page      = new Integer(request.getParameter("p"));
                final int pageSize  = new Integer(request.getParameter("ps"));
                final int contactID = new Integer(request.getParameter("c"));

                ObjectOutputStream oos = new ObjectOutputStream(resp.getOutputStream());
                oos.writeObject(profileFacade.browseVideoGallery(authItem, contactID, page, pageSize));
            } else if ("gvt".equalsIgnoreCase(ac)) {// get video thumbnail
                final String q = request.getParameter("q");
                final String path = profileFacade.getVideoThumbPath(new Long(q));

                writeImageOntoResponse(request, resp, path, Integer.parseInt(request.getParameter("w")), Integer.parseInt(request.getParameter("h")));
            } else if ("st".equalsIgnoreCase(ac)) {// stream video
                final String q = request.getParameter("q");
                final String path = profileFacade.getVideoPathAndIncreaseViewCounter(new Long(q));
//                String path = "/home/rafael/dev/img_test_data/video-2009-04-27-21-35-17.3gp";

                streamBinaryData(path, request, resp);
                
//                writeImageOntoResponse(request, resp, path, Integer.parseInt(request.getParameter("w")), Integer.parseInt(request.getParameter("h")));
            } 
	    } catch (Exception e) {
	        e.printStackTrace();
        }
	}
	
	private String uploadVideo(HttpServletRequest request, HttpServletResponse resp, String videoID, String mimeType) {
        try {
            InputStream in = new DataInputStream(request.getInputStream());
            final String fileName = IConstants.ROOT_FOR_VIDEOS + videoID + getMimeTypeExtension(mimeType);
            
            IOUtilities.ensureDirectory(fileName);
            
            final FileOutputStream fos = new FileOutputStream(fileName);
            OutputStream out = new BufferedOutputStream(fos, 4 * 1024);
            byte[] b = new byte[4 * 1024];
            int read;
            while ((read = in.read(b)) != -1) {
                out.write(b, 0, read);
            }
            out.flush();
            
            return fileName;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
	
	private String getMimeTypeExtension(String mimeType) {
        if("image/jpeg".equalsIgnoreCase(mimeType)) return ".jpg";
        if("video/mp4".equalsIgnoreCase(mimeType)) return ".3gp";
        return null;
    }
	
    private void writeImageOntoResponse(HttpServletRequest request, HttpServletResponse resp, String filename, int width, int height) throws IOException {
        // Get the absolute path of the image
        ServletContext sc = getServletContext();

        // Get the MIME type of the image
        String mimeType = sc.getMimeType(filename);
        if (mimeType == null) {
            System.out.println("Could not get MIME type of " + filename);
            sc.log("Could not get MIME type of " + filename);
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }

        // Set content type
        resp.setContentType(mimeType);

        // Open the file and output streams
        FileInputStream in = null;
        OutputStream out = null;
        try {
            // Set content size
            File file = new File(filename);
            // resp.setContentLength((int)file.length());

            in = new FileInputStream(file);

            if (request.getHeader("Accept-Encoding").contains("gzip")) {
                out = new GZIPOutputStream(resp.getOutputStream());
                resp.setHeader("Content-Encoding", "gzip");
            } else {
                out = resp.getOutputStream();
            }

            Thumbnail.createThumb(Toolkit.getDefaultToolkit().getImage(filename), width, height, 100, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            in.close();
            out.close();
        }
    }
	
	/**
     * This Method Handles streaming Binary data
     * <p>
     * 
     * @param String
     *            urlstr ex: http;//localhost/test.pdf etc.
     * @param String
     *            format ex: pdf or audio_wav or msdocuments etc.
     * @param ServletOutputStream
     *            outstr
     * @param HttpServletResponse
     *            resp
     */
    private void streamBinaryData(String filename, HttpServletRequest request, HttpServletResponse resp) {
        try {
//            // Get the absolute path of the image
//            ServletContext sc = getServletContext();
//
//            // Get the MIME type of the image
//            String mimeType = sc.getMimeType(filename);
//            if (mimeType == null) {
//                System.out.println("Could not get MIME type of " + filename);
//                sc.log("Could not get MIME type of " + filename);
//                resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
//                return;
//            }

            // find the right mime type and set it as contenttype
//            resp.setContentType(getMimeType(mimeType));
            
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            InputStream in = null;
            OutputStream out = null;
            try {
                final String encoding = request.getHeader("Accept-Encoding"); 
                if (encoding != null && encoding.contains("gzip")) {
                    out = new GZIPOutputStream(resp.getOutputStream());
                    resp.setHeader("Content-Encoding", "gzip");
                } else {
                    out = resp.getOutputStream();
                }

                // VERY IMPORTANT: without this crap, the thing doesnt work
                int length = (int) new File(filename).length();
                resp.setContentLength(length);
                resp.setContentType("video/avi");//TODO: hard coded?????

                // Use Buffered Stream for reading/writing.
                in = new FileInputStream(filename);
                bis = new BufferedInputStream(in);
                bos = new BufferedOutputStream(out);
                byte[] buff = new byte[length];
                int bytesRead;
                // Simple read/write loop.
                while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                    bos.write(buff, 0, bytesRead);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null)
                    in.close();

                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
                if (out != null) {
                    out.flush();
                    out.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

	  /*
	   * This Method Returns the right mime type for a particular  format
	   * <p>
	   * @param String format ex: xml or html etc.
	   * @return String mimetype
	   */
//	      private String getMimeType(String format)
//	      {
//	            if(format.equalsIgnoreCase("pdf")) //check the out type
//	                return "application/pdf";
//	            else if(format.equalsIgnoreCase("audio_basic"))
//	                return "audio/basic";
//	            else if(format.equalsIgnoreCase("audio_wav"))
//	                return "audio/wav";
//                else if(format.equalsIgnoreCase("audio_mpeg"))
//                    return "audio/mpeg";
//	            else if(format.equalsIgnoreCase("image_gif"))
//	                return "image/gif";
//	            else if(format.equalsIgnoreCase("image_jpeg"))
//	                return "image/jpeg";
//	            else if(format.equalsIgnoreCase("image_bmp"))
//	                return "image/bmp";
//	            else if(format.equalsIgnoreCase("image_x-png"))
//	                return "image/x-png";
//	            else if(format.equalsIgnoreCase("msdownload"))
//	                return "application/x-msdownload";
//	            else if(format.equalsIgnoreCase("video_avi"))
//	                return "video/avi";
//	            else if(format.equalsIgnoreCase("video_mpeg"))
//	                return "video/mpeg";
//	            else if(format.equalsIgnoreCase("html"))
//	                return "text/html";
//	            else if(format.equalsIgnoreCase("xml"))
//	                return "text/xml";
//	            else
//	                return format;
//	      }
}
